進化的アーキテクチャ ―― 絶え間ない変化を支える
https://images-na.ssl-images-amazon.com/images/I/51mS9i-00uL._SX350_BO1,204,203,200_.jpg
概要
思想的な内容で、「どう実現するか」 や 「何を実現するか」 の詳細よりも、抽象的な内容が主
進化的アーキテクチャの基本的な側面は次の 3 つ
漸進的な変更
適切な結合
どう実現するか
1. 進化の影響を受ける次元を特定する
内容メモ
小さな変更を加える
1 章 ソフトウェアアーキテクチャ
高度に動的なシステムに変化を取り込むことは、予期せぬ結果を生じさせうる 技術やドメインにおける環境変化がいつ起こるかわからないが、変化は避けられない → 変化する前提でシステムを設計する必要
順応する必要
環境が変わらないとしても、ビットロット (経年劣化) から保護する必要はある 進化可能性は他の全てのアーキテクチャ特性を保護するメタ特性 本書では、第一級のアーキテクチャ要素として、時間と変化を加える
漸進的な変更は、ソフトウェアアーキテクチャの 2 つの側面を表現
チームがどう漸進的にソフトウェアを構築するか
それをどう漸進的にデプロイするか
アーキテクチャの変更を誘導するために適応度関数を導入 進化可能なアーキテクチャを作るには、変更を与える全ての部分を考慮する必要
アーキテクチャを概念的に切り分ける技法はいろいろあるが……
本書では次元の分類を作成するのではなく、現在のプロジェクトが有する次元を捉えることをしていく
変更したい対象が他の誰かのものなら、それを変更することは難しい
ソフトウェアアーキテクトは、チーム構造をアーキテクチャ上の目標にあわせるために仕事を移譲したり分割したりする方法についても注意を払う必要 チーム構造はソフトウェア開発の無数の次元に影響するものだから
漸進的
誘導的
2 章 適応度関数
進化的アーキテクチャにおける適応度関数は、必ずしもソフトウェアで実装できない場合もある (手作業の場合もある)
例えば循環的複雑度を一定以下にする、というようなものも適応度関数として使用できる 適応度関数は早期に特定すべき
大きなシステムを、より小さな適応度関数の集合を扱う小さなシステムに分割するのも助ける
3 章 漸進的な変更を支える技術
漸進的な変更 → アーキテクチャは小さく漸進的な変更を容易にしなければならない
2 つの側面
開発 : 開発者がソフトウェアを構築する
運用 : チームがソフトウェアをデプロイする
ソフトウェアに静的なものはない
環境の方がどんどん変わっていくので、合理的なアーキテクチャ計画には進化的変更を含める必要
時間軸を考慮する必要 ← 4 次元で考える (本書だと、3 次元目が実装詳細 (?) で、4 次元目が時間軸、という感じっぽい)
テスト可能性は無視されがちだが、アーキテクチャの一部はテストによる検証が容易 適応度関数は任意の所有者を持つことが可能 (共同所有を含む) ユーザーは小さな変更が頻繁に大量に現れることを望んではいない → 機能トグルを使用するなどする 機能トグルを使うことで、本番環境で QA タスクを実行できるようになる
例
本番コード上で、信頼できる古いやり方と新しいやり方を比較する (結果はもちろん、パフォーマンス等も)
4 章 アーキテクチャ上の結合
結合は必要悪だとみなされがちだが、結合なしに複雑なソフトウェアを構築することは困難
→ 最小のオーバーヘッドで最大の利益を得るために結合すべきアーキテクチャの次元を特定する
アーキテクチャの議論で古くから使われてきた用語
全てのモジュール機構はコードの再利用を容易にする ← あらゆるレベルでコードを再利用することは賢明 コンポーネント : モジュールを物理的にパッケージする方法 (物理的な分割方法) ライブラリ : 呼び出し側のコードと同じメモリアドレス内で実行されるコンポーネント サービス : 独自のアドレス空間で実行されるコンポーネント システムが適切に機能するために必要なものをすべて含む
代表的なアーキテクチャパターン
進化させていくことは困難
nobuoka.icon 巨大な泥団子よりはマシらしいが、あんまり違いがわからん
これが流行っていた当時は、オープンソースシステムの活用はあまりされていなかった → マイクロサービスのようなインスタンス数が多いものは採用されにくかった 多くのソフトウェアアーキテクチャは技術的な次元に焦点をあてているが、マイクロサービスはドメインの次元に焦点を当てる
進化の観点で優れている
アーキテクチャの量子サイズが小さいほど、進化的な変更は容易になる
5 章 進化的データ
データは進化可能なアーキテクチャを作る際に考慮すべき重要な次元
データベース構造に対しても、ソースコードを処理するのと同じようにテストして、バージョン管理して、漸進的に進むべし
不適切な結合
アーキテクチャの結合の議論は技術アーキテクチャの各側面に注目しがちだが、トランザクションも結合につながる
データベースによる結合には、ビジネスプロセスがどう動くかが定義されていることがあり、技術アーキテクチャによる結合よりもずっと負荷が大きい
データとデータベースの神格化は大企業に見られる機能不全
データベースをリファクタリングせずに、別の交差テーブルを追加する
6 章 進化可能なアーキテクチャの構築
進化的アーキテクチャの構築に役立つ 3 つの手順
1. 進化の影響を受ける次元を特定する
組織内でそれに関心を示すチームが関与する必要があるので、逆コンウェイ戦略が役立つ 既存のアーキテクチャの改良
既存アーキテクチャに進化可能性を加えられるかどうかは 3 つの要因によって決まる
コンポーネント結合 (適切な結合と凝集)
結合の技術的な側面を超えて、コンポーネントの機能的凝集についても考慮が必要 開発プラクティスの成熟度
進化的アーキテクチャの構築における唯一最大の障害は扱いにくい運用 変更を容易にデプロイできなければ、フィードバックサイクルの全ての部分が妨害される
適応度関数のつくりやすさ
エコシステムの構成要素の一部を所有していないことで、進化可能なシステムを構築する際の困難
メタ作業 (他の開発者が使うフレームワークを作るなど) は単なる作業よりも面白いため、それをしたがる開発者が多い
既存のものを使えるのにメタ作業ができるというだけで新しいアーキテクチャを構築するのはやめろ
アーキテクチャの移行
いきなり全体をマイクロサービスに分割するのではなく、モノリスを少数のサービスに分割するところから
トランザクション境界の分離が困難のひとつ
正しいサービスの粒度を見つけることが重要
分割方法の例
デプロイメント目標 : コンポーネントごとのリリース速度や可用性などの運用特性によって決める
モジュール自体を複製する方法もある
サービス分割を特定した後は、UI とビジネスロジックを分離
UI で情報を統合して表示する必要があるため、UI がしばしばモノリスに引き戻す → UI を分離しておく
呼び出しポイントの修正
進化可能アーキテクチャ構築の手引き
脳の進化は、古い層 (呼吸を無意識に行うような) の上に新しい層を積み重ねてきた 大企業のソフトウェアアーキテクチャも同様
DevOps のベストプラクティスの多くは、可逆可能な判断 (元に戻す必要のある決定) を可能にする 未知の未知はソフトウェアシステムの元凶 → 予測可能性ではなく進化可能性を選べ アジャイルアーキテクトは、意思決定における最終責任時点原則を重んじる nobuoka.icon 意思決定はできるだけ延期させる、というものっぽい
外部への依存に対して、開発者は利益を意識していても、制約・コストについては無視しがち
我々のコードがライブラリを呼び出すのに対して、フレームワークは我々のコードを呼び出す
フレームワークはアプリケーションのコードの基盤なので、バージョンアップに速やかに追従していく必要
外部依存関係に 2 つの指定を導入することを提案
不安定な依存関係 : 自動的に新しいバージョンに更新
保護された依存関係
エンドポイントへのバージョン付け
ナンバリング : エンドポイントにバージョン番号を含めるような形 (新しいバージョンは新しいエンドポイント)
内部解決 : 呼び出し元は同じエンドポイントを呼び、呼ばれた側が適切なバージョンを選択
nobuoka.icon 具体的にどうやるんだろ
7 章 進化的アーキテクチャの落とし穴とアンチパターン
技術アーキテクチャについて
ベンダーキングアンチパターンを避けるために、ベンダー製品は単なる統合点として扱う 抽象化が望ましくない方法で欠如しないよう、適応度関数で保護する
漸進的な変更について
ビジネス上の関心事
製品のカスタマイズは落とし穴のひとつ
カスタマイズはコストがかかるので、進化を妨げる
だからといってカスタマイズ可能な製品の構築を禁止すべきではないが、関連するコストの現実的な評価が必要
レポート機能はアンチパターンになりやすい
レポート機能のために直接 DB を参照することは、進化を妨げる
広い計画範囲は落とし穴
少ない情報で多くの判断や仮説が行われる
→ 選択肢を開いたままにする方法を考えること
8 章 進化的アーキテクチャの実践
ソフトウェアアーキテクチャの影響は広範囲 → チーム編成や予算編成にも影響
ドメインを中心にアーキテクチャとチームをモデリングすることで、共通の変更の単位が同じチームにより処理される → 人為的な摩擦が減少
プロダクトチームは、プロダクトの長期的な品質に所有責任を持つことになる
チームがうまくいくかどうかはチームの人数ではなくチームが維持すべき人のつながりの数に依存
→ 小さな機能横断型のチームが良い
アーキテクトはチーム構造がアーキテクチャの結合特性に与える影響も考慮すべし うまく機能するアーキテクトは、リーダーシップを発揮し、技術文化を作り、進化的アーキテクチャ構築に必要なスキルを個々のエンジニアに伝えていく
小さく実験 (技術的にもプロダクト的にも) し、うまくいったものを既存のシステムへと統合する
様々な方法
セットベース開発に従い、短い期間 (数日未満) でいくつかのアプローチをプロトタイプする アーキテクチャの量子数と量子当たりのコストは、量子が増えるほど減少する (スイートスポットに達するまで)
アーキテクチャ内の意図的な結合点とプラットフォームの選択についての手引き
既存のアーキテクチャに進化可能性を付け加えるためにどこから始めるか?
低い位置にぶらさがった果実
効果のあるもっとも簡単な問題を最初に
モジュール性を高めて結合を分離することで、適応度関数と漸進的な変更という進化的アーキテクチャの側面を実証
nobuoka.icon 原文どんなんだろ
最大限の価値あるものを最初に
開発と運用の壁を取り払う
実際に運用されているアプリケーションに接することができない状態で、開発者が混乱をほどくのは難しい
進化的アーキテクチャの将来の展望
なぜ進化的アーキテクチャに取り組むか
企業は予測可能性を評価する (戦略的な問題の長期的な計画) が、それが有効でない世界になっているため ソフトウェア開発における動的平衡は予測可能性の効力を失わせた
スケールさせるため
従来、アーキテクチャのベストプラクティスはリレーショナルデータベースをバックエンドにしたトランザクションシステムを構築し、データベースの多くの機能を使用して調整を行うことだった
このアプローチの問題はスケーリング
高度なビジネス機能を実現するため
ビジネスメトリクスとしてのサイクルタイムの改善のため
大規模で保守的な企業では、ソフトウェアをオーバーヘッドとしてとらえ、コストを最小限に抑えようとする
イノベーティブな企業では、ソフトウェアを競争上の優位性とみなす
競争の激しい市場の企業は、サイクルタイムを第一級のビジネスメトリクスとする 量子レベルでアーキテクチャ特性を分離するため
進化的アーキテクチャの構築を決断すべきでないのはどういうときか
実現可能性が低いとき (再構築した方がコストがかからないとき) 既存のシステムのモジュール性を見出して、それを中心に再構築できるかを考える 進化可能性を捨ててでも実現すべきアーキテクチャの特性がある場合 ビジネスをまもなく閉じる予定であるとき
進化的アーキテクチャを実施すべきことを他者に説得ことに苦労 → 説得よりも実証
痛みがある場所を直していく